﻿using Basic.FlowCollect;
using Basic.FlowExtendService;
using Basic.FlowLocalEvent.Model;
using Basic.FlowModel.DB;
using Basic.FlowModel.Flow;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Flow.Model;
using Basic.FlowService.Interface;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;
using WeDonekRpc.Model;

namespace Basic.FlowService.lmpl
{
    internal class FlowService : IFlowService
    {
        private readonly IFlowCollect _Flow;
        private readonly IEmpService _Emp;
        private readonly IFormService _Form;
        private readonly IFlowAuditLogCollect _AuditLog;

        public FlowService ( IFlowCollect flow,
            IEmpService emp,
            IFlowAuditLogCollect auditLog,
            IFormService form )
        {
            this._Flow = flow;
            this._AuditLog = auditLog;
            this._Emp = emp;
            this._Form = form;
        }

        public long Add ( FlowAdd add )
        {
            return this._Flow.Add(add);
        }
        public string GetFlowName ( long id )
        {
            return this._Flow.GetFlowName(id);
        }
        public FlowChildren GetChildren ( long id )
        {
            FlowBase[] dbs = this._Flow.GetChildren<FlowBase>(id);
            if ( dbs.IsNull() )
            {
                throw new ErrorException("flow.not.find");
            }
            FlowChildren sour = dbs.ConvertFind<FlowBase, FlowChildren>(a => a.SourceId.HasValue == false);
            if ( dbs.Length > 1 )
            {
                sour.Children = dbs.ConvertMap<FlowBase, FlowChildren>(a => a.SourceId == sour.Id);
            }
            return sour;
        }

        public void Delete ( long id )
        {
            DBFlowList sour = this._Flow.Get(id);
            if ( sour.Status != FlowStatus.起草 && sour.SourceId.HasValue == false )
            {
                throw new ErrorException("flow.status.error");
            }
            else if ( sour.Status == FlowStatus.启用 && sour.SourceId.HasValue )
            {
                throw new ErrorException("flow.status.error");
            }
            else if ( sour.SourceId.HasValue && this._AuditLog.CheckIsUse(sour.Id) )
            {
                throw new ErrorException("flow.already.use");
            }
            this._Flow.Delete(sour);
            new FlowEvent(sour).AsyncSend("Delete");
        }

        public FlowDto Get ( long id )
        {
            DBFlowList sour = this._Flow.Get(id);
            return sour.ConvertMap<DBFlowList, FlowDto>();
        }

        public PagingResult<FlowData> Query ( FlowQueryParam query, IBasicPage paging )
        {
            DBFlowList[] list = this._Flow.Query<DBFlowList>(query, paging, out int count);
            if ( list.IsNull() )
            {
                return new PagingResult<FlowData>();
            }
            FlowData[] dtos = list.ConvertMap<DBFlowList, FlowData>();
            DBFlowList[] subs = this._Flow.GetChildren<DBFlowList>(list.ConvertAll(a => a.Id));
            List<long> empId = dtos.Select(c => c.CreateBy).ToList();
            List<long> formId = dtos.Where(a => a.DefFormId.HasValue).Select(c => c.DefFormId.Value).ToList();
            if ( subs.Length > 0 )
            {
                subs.ForEach(a =>
                {
                    empId.Add(a.CreateBy);
                    if ( a.DefFormId.HasValue )
                    {
                        formId.Add(a.DefFormId.Value);
                    }
                });
            }
            Dictionary<long, string> formName = this._Form.GetName(formId.Distinct().ToArray());
            Dictionary<long, string> emp = this._Emp.GetNames(empId.Distinct().ToArray());
            dtos.ForEach(c =>
            {
                if ( c.DefFormId.HasValue )
                {
                    c.FormName = formName.GetValueOrDefault(c.DefFormId.Value);
                }
                c.CreateName = emp.GetValueOrDefault(c.CreateBy);
                c.Children = subs.Convert(a => a.SourceId == c.Id, a => new FlowData
                {
                    SourceId = a.SourceId,
                    DefFormId = a.DefFormId,
                    CreateBy = a.CreateBy,
                    CreateName = emp.GetValueOrDefault(a.CreateBy),
                    CreateTime = a.CreateTime,
                    FlowName = a.FlowName,
                    Children = null,
                    FlowType = a.FlowType,
                    FormName = a.DefFormId.HasValue ? formName.GetValueOrDefault(a.DefFormId.Value) : null,
                    Id = a.Id,
                    Status = a.Status,
                    VerNum = a.VerNum,
                    Remark = a.Remark,
                });
            });
            return new PagingResult<FlowData>(dtos, count);
        }

        public bool Set ( long id, FlowSet set )
        {
            DBFlowList sour = this._Flow.Get(id);
            if ( sour.Status == FlowStatus.停用 )
            {
                set.DefFormId = sour.DefFormId;
            }
            return this._Flow.Set(sour, set);
        }

        public bool Stop ( long id )
        {
            DBFlowList sour = this._Flow.Get(id);
            if ( this._Flow.SetStatus(sour, FlowStatus.停用) )
            {
                new FlowEvent(sour).AsyncSend("Stop");
                return true;
            }
            return false;
        }
    }
}
